package cn.sms.basic.service.impl;

import cn.sms.basic.constant.UserConstants;
import cn.sms.basic.dto.LoginDto;
import cn.sms.basic.exception.BusinessException;
import cn.sms.basic.service.ILoginService;
import cn.sms.basic.util.AjaxResult;
import cn.sms.basic.util.HttpClientUtils;
import cn.sms.basic.util.MD5Utils;
import cn.sms.basic.util.StrUtils;
import cn.sms.user.domain.Logininfo;
import cn.sms.user.domain.User;
import cn.sms.user.domain.WxUser;
import cn.sms.user.mapper.LogininfoMapper;
import cn.sms.user.mapper.UserMapper;
import cn.sms.user.mapper.WxUserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Map goToLogin(LoginDto dto) {
        if(StringUtils.isEmpty(dto.getUsername())||StringUtils.isEmpty(dto.getPassword())){
            throw new BusinessException("请填写相应的内容");
        }
        Logininfo logininfo = logininfoMapper.byQueryUsername(dto.getUsername());
        if(logininfo ==null){
            throw new BusinessException("用户名错误");
        }
        String salt = logininfo.getSalt();
        String dtoPassword = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        String password = logininfo.getPassword();
        if(!password.equals(dtoPassword)){
            throw new BusinessException("密码错误");
        }
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        Map map = new HashMap<>();
        map.put("token", token);
        logininfo.setSalt("");
        logininfo.setPassword("");
        map.put("logininfo", logininfo);
        return map;
    }

    @Override
    public AjaxResult goWechat(Map<String, String> param) {
        String code = param.get("code");
        if(code==null){
            throw new BusinessException("参数不能为空");
        }
        String getTokenUrl = UserConstants.WXUSER_GET_TOKEN
                .replace("APPID", UserConstants.APPID)
                .replace("SECRET", UserConstants.SECRET)
                .replace("CODE", code);
        String tokenStr = HttpClientUtils.httpGet(getTokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(tokenStr);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if(wxUser != null && wxUser.getUser_id() != null){
            Logininfo logininfo = logininfoMapper.byUserId(wxUser.getUser_id());
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
            Map map = new HashMap<>();
            map.put("token", token);
            logininfo.setSalt("");
            logininfo.setPassword("");
            map.put("logininfo", logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        //wxUser为空就是不存在就跳去绑定
        String binder = "?accessToken="+accessToken+"&openId="+openId;
        return AjaxResult.me().setSuccess(false).setResultObj(binder);
    }

    @Override
    public Map<String,Object> binder(Map<String, String> param) {
        if(StringUtils.isEmpty(param.get("phone"))
                ||StringUtils.isEmpty(param.get("verifyCode"))
                ||StringUtils.isEmpty(param.get("accessToken"))
                ||StringUtils.isEmpty(param.get("openId"))){
            throw new BusinessException("参数不能为空");
        }
        /*
         * key = "Verifycode:"+phone;
         * value = xxxxxx:时间戳
         */
        String key = UserConstants.PHONE_BINDER+param.get("phone");
        Object value = redisTemplate.opsForValue().get(key);
        if(value == null){
            throw new  BusinessException("验证码失效，请重新获取");
        }
        String code = value.toString().split(":")[0];
        if(!code.equals(param.get("verifyCode"))){
            throw new BusinessException("验证码错误");
        }
        User user = userMapper.byPhoneQuery(param.get("phone"));
        Logininfo logininfo = null;
        if(user != null){
            logininfo = logininfoMapper.loadId(user.getLogininfo_id());
        }else {
            user = user(param);
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfo_id(logininfo.getId());
            userMapper.save(user);
        }
        //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
        String getWxUser = UserConstants.GET_WXUSER_USER
                .replace("ACCESS_TOKEN", param.get("accessToken"))
                .replace("OPENID", param.get("openId"));
        String newsStr = HttpClientUtils.httpGet(getWxUser);
        WxUser wxUser = JSONObject.parseObject(newsStr, WxUser.class);
        wxUser.setUser_id(user.getId());
        wxUserMapper.save(wxUser);
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        Map map = new HashMap<>();
        map.put("token", token);
        logininfo.setSalt("");
        logininfo.setPassword("");
        map.put("logininfo", logininfo);
        return map;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        return logininfo;
    }

    private User user(Map<String, String> param) {
        User user = new User();
        user.setUsername(param.get("phone"));
        user.setPhone(param.get("phone"));
        String salt = StrUtils.getComplexRandomString(32);
        String password = MD5Utils.encrypByMd5("1"+salt);
        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }
}
